import React from 'react';

interface JsonViewerProps {
  content: string;
  isOwn?: boolean;
}

type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
interface JsonObject { [key: string]: JsonValue }
type JsonArray = JsonValue[];

// CSS类定义
const jsonViewerClasses = {
  fontSize12: 'text-xs',
  transformUp3: 'transform translate-y-1',
  iconSize14: 'w-3.5 h-3.5',
  colonColor: 'text-gray-400',
  commaColor: 'text-gray-400',
  keyStyle: 'text-blue-600',
  stringStyle: 'text-green-600',
  numberStyle: 'text-red-600',
  booleanStyle: 'text-yellow-600'
};

export function JsonViewer({ content, isOwn = false }: JsonViewerProps) {
  let parsed: JsonValue | null = null;
  try {
    parsed = JSON.parse(content);
    if (parsed && typeof parsed !== 'object') parsed = null;
  } catch {
    parsed = null;
  }

  if (parsed === null) {
    return (
      <pre className={`whitespace-pre overflow-x-auto ${isOwn ? 'text-white' : 'text-gray-900'} ${jsonViewerClasses.fontSize12}`}>{content}</pre>
    );
  }

  return (
    <div className={`relative font-mono text-gray-900 ${jsonViewerClasses.fontSize12}`}>
      <div className={`rounded border ${isOwn ? 'border-white/40 bg-white/15' : 'border-gray-200 bg-white'}`}>
        <pre className={`p-3 overflow-x-auto whitespace-pre ${jsonViewerClasses.fontSize12}`}>
          <JsonNode value={parsed} level={0} isOwn={isOwn} forceAllExpanded={undefined} />
        </pre>
      </div>
    </div>
  );
}

function JsonNode({ value, level, isOwn, forceAllExpanded }: { value: JsonValue; level: number; isOwn: boolean; forceAllExpanded?: boolean }) {
  const [expanded, setExpanded] = React.useState(false);
  const [allExpanded, setAllExpanded] = React.useState(false);
  const nodeRef = React.useRef<HTMLSpanElement | null>(null);

  // 当父级强制设置全部展开状态时，同步更新本地状态
  React.useEffect(() => {
    if (forceAllExpanded !== undefined) {
      setAllExpanded(forceAllExpanded);
    }
  }, [forceAllExpanded]);

  if (Array.isArray(value)) {
    if (value.length === 0) return <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>[]</span>;
    return (
      <span ref={nodeRef}>
        <CopyNodeButton onCopy={() => navigator.clipboard.writeText(JSON.stringify(value, null, 2))} />
        <ToggleAllSmallButton
          expandedAll={allExpanded}
          onToggle={() => {
            const root = nodeRef.current;
            if (root) {
              const next = !allExpanded;
              toggleAll(root, next);
              setAllExpanded(next);
              if (next && !expanded) setExpanded(true);
            }
          }}
        />
        <Toggle expanded={expanded} onToggle={() => setExpanded(!expanded)} />
        <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>[</span>
        {expanded ? (
          <div className="pl-4 border-l border-dotted border-gray-300">
            {value.map((item, idx) => (
              <div key={idx} className="whitespace-nowrap">
                <JsonNode value={item} level={level + 1} isOwn={isOwn} forceAllExpanded={allExpanded} />{idx < value.length - 1 ? ',' : ''}
              </div>
            ))}
          </div>
        ) : (
          <span className={`italic text-gray-400 ${jsonViewerClasses.fontSize12}`}>[...] ({value.length} items)</span>
        )}
        <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>]</span>
      </span>
    );
  }

  if (value && typeof value === 'object') {
    const entries = Object.entries(value as JsonObject);
    if (entries.length === 0) return <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>{'{}'}</span>;
    return (
      <span ref={nodeRef}>
        <CopyNodeButton onCopy={() => navigator.clipboard.writeText(JSON.stringify(value, null, 2))} />
        <ToggleAllSmallButton
          expandedAll={allExpanded}
          onToggle={() => {
            const root = nodeRef.current;
            if (root) {
              const next = !allExpanded;
              toggleAll(root, next);
              setAllExpanded(next);
              if (next && !expanded) setExpanded(true);
            }
          }}
        />
        <Toggle expanded={expanded} onToggle={() => setExpanded(!expanded)} />
        <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>{`{`}</span>
        {expanded ? (
          <div className="pl-4 border-l border-dotted border-gray-300">
            {entries.map(([k, v], idx) => (
              <div key={k} className="whitespace-nowrap">
                <span className={`${jsonViewerClasses.keyStyle} ${jsonViewerClasses.fontSize12}`}>"{k}"</span>
                <span className={`${jsonViewerClasses.colonColor} ${jsonViewerClasses.fontSize12}`}>: </span>
                <JsonNode value={v} level={level + 1} isOwn={isOwn} forceAllExpanded={allExpanded} />
                {idx < entries.length - 1 ? <span className={`${jsonViewerClasses.commaColor} ${jsonViewerClasses.fontSize12}`}>,</span> : null}
              </div>
            ))}
          </div>
        ) : (
          <span className={`inline-flex items-center italic text-gray-400 ${jsonViewerClasses.fontSize12}`}>
            <span>{'{}'}</span>
            <span className="ml-1">({entries.length} keys)</span>
          </span>
        )}
        <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>{`}`}</span>
      </span>
    );
  }

  if (typeof value === 'string') return <span className={`${jsonViewerClasses.stringStyle} ${jsonViewerClasses.fontSize12}`}>"{value}"</span>;
  if (typeof value === 'number') return <span className={`${jsonViewerClasses.numberStyle} ${jsonViewerClasses.fontSize12}`}>{value}</span>;
  if (typeof value === 'boolean') return <span className={`${jsonViewerClasses.booleanStyle} ${jsonViewerClasses.fontSize12}`}>{String(value)}</span>;
  if (value === null) return <span className={`text-gray-500 ${jsonViewerClasses.fontSize12}`}>null</span>;
  return <span className={jsonViewerClasses.fontSize12}>{String(value)}</span>;
}

function Toggle({ expanded, onToggle }: { expanded: boolean; onToggle: () => void }) {
  return (
    <button
      className={`inline-flex items-center mr-1 opacity-70 hover:opacity-100 ${jsonViewerClasses.transformUp3}`}
      onClick={onToggle}
      title={expanded ? '折叠' : '展开'}
      data-node-toggle="true"
      data-expanded={expanded}
    >
      {expanded ? (
        <img src="/public/images/collapse-node.svg" className={`${jsonViewerClasses.iconSize14}`} />
      ) : (
        <img src="/images/expand-node.svg" className={`${jsonViewerClasses.iconSize14}`} />
      )}
    </button>
  );
}

async function toggleAll(root: HTMLElement, expand: boolean) {
  const nextFrame = () => new Promise(requestAnimationFrame);
  
  // 处理展开/折叠按钮
  const selector = expand
    ? 'button[data-node-toggle="true"][data-expanded="false"]'
    : 'button[data-node-toggle="true"][data-expanded="true"]';
  // 循环点击并在每轮后等待一帧，让React完成渲染，再继续向下递归
  // 直到没有符合条件的按钮为止
  // 加一层安全阈值避免极端情况下的无限循环
  let guard = 0;
  while (guard++ < 1000) {
    const buttons = root.querySelectorAll(selector);
    if (buttons.length === 0) break;
    buttons.forEach((btn) => (btn as HTMLButtonElement).click());
    await nextFrame();
  }
}

// Note: node-level copy was removed per user's latest request (only keep per-node expand behaviors)

function ToggleAllSmallButton({ expandedAll, onToggle }: { expandedAll: boolean; onToggle: () => void }) {
  return (
    <button className={`inline-flex items-center mr-1 opacity-70 hover:opacity-100 ${jsonViewerClasses.transformUp3}`} onClick={onToggle} title={expandedAll ? '全部折叠' : '全部展开'}>
      {expandedAll ? <img src="/images/collapse.svg" className="w-3.5 h-3.5" /> : <img src="/images/expand.svg" className="w-3.5 h-3.5" />}
    </button>
  );
}

function CopyNodeButton({ onCopy }: { onCopy: () => void }) {
  const [copied, setCopied] = React.useState(false);
  const doCopy = async () => {
    try {
      // 优先使用传入复制逻辑
      await onCopy();
      setCopied(true);
      setTimeout(() => setCopied(false), 1200);
    } catch {
      // 兜底：使用选区复制
      try {
        const sel = window.getSelection?.();
        const range = document.createRange();
        const tmp = document.createElement('textarea');
        tmp.value = '';
        document.body.appendChild(tmp);
        tmp.select();
        document.execCommand('copy');
        document.body.removeChild(tmp);
        if (sel) {
          sel.removeAllRanges();
          sel.addRange(range);
        }
        setCopied(true);
        setTimeout(() => setCopied(false), 1200);
      } catch (fallbackError) {
        console.warn('Fallback copy failed:', fallbackError);
      }
    }
  };
  return (
    <button className={`inline-flex items-center mr-1 opacity-70 hover:opacity-100 ${jsonViewerClasses.transformUp3}`} onClick={doCopy}>
      <img src={copied ? '/public/images/gou.png' : '/public/images/fuzhi.png'} className="w-3.5 h-3.5" />
    </button>
  );
}


